package com.xlh.websocket;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import com.xlh.enums.WebsocketMessageEnum;
import com.xlh.pojo.UserMessageDetails;
import com.xlh.support.attendance.service.AttendanceService;
import com.xlh.support.attendance.websocket.message.AttendanceBeginMessage;
import com.xlh.util.SpringContextUtil;
import com.xlh.websocket.message.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.List;

/**
 * 全局WebSocket
 *
 * @author cheer
 */
@ServerEndpoint(value = "/ws/global", configurator = GetHttpSessionConfigurator.class)
@Component
@Slf4j
public class GlobalWebsocket {

    private static final ObjectMapper objectMapper = SpringContextUtil.getBean(ObjectMapper.class);

    private static final AttendanceService attendanceService = SpringContextUtil.getBean(AttendanceService.class);

    /**
     * 存储所有连接 key为userId
     */
    private static ListMultimap<Long, GlobalWebsocket> connectionMap = Multimaps.synchronizedListMultimap(ArrayListMultimap.create());

    private Session session;

    /**
     * 用户Id
     */
    private Long userId;

    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        this.session = session;
        this.userId = (Long) config.getUserProperties().get("userId");
        connectionMap.put(userId, this);

        if (attendanceService.isAttendanceRunning(this.userId)) {
            AttendanceBeginMessage attendanceBeginMessage = AttendanceBeginMessage.builder()
                    .userId(this.userId)
                    .build();
            try {
                session.getBasicRemote().sendText(objectMapper.writeValueAsString(attendanceBeginMessage));
            } catch (JsonProcessingException e) {
                log.error("json process exception", e);
            } catch (IOException e) {
                log.warn("websocket send message exception", e);
            }
        }
    }

    @OnClose
    public void onClose() {
        connectionMap.remove(userId, this);
    }

    @OnMessage
    public void onMessage(String jsonStr, Session session) {
        // 暂时不需要实现该方法
    }

    @OnError
    public void onError(Session session, Throwable error) {
        // 暂时不需要实现该方法
    }

    /**
     * 发送消息
     *
     * @param userId  接收消息用户
     * @param message 消息内容
     */
    public static void sendMessage(Long userId, Message message) {
        try {
            String sendMessage = objectMapper.writeValueAsString(message);
            sendMessage(userId, sendMessage);
        } catch (JsonProcessingException e) {
            log.error("json process exception", e);
        }
    }

    /**
     * 发送消息
     *
     * @param userIds 接受消息的用户Id集合
     * @param message 消息内容
     */
    public static void sendMessage(List<Long> userIds, Message message) {
        try {
            String sendMessage = objectMapper.writeValueAsString(message);
            for (Long userId : userIds) {
                sendMessage(userId, sendMessage);
            }
        } catch (JsonProcessingException e) {
            log.error("json process exception", e);
        }
    }

    /**
     * 发送消息
     *
     * @param userId  接受消息的用户Id
     * @param message 消息内容
     */
    private static void sendMessage(Long userId, String message) {
        List<GlobalWebsocket> globalWebsocketList = connectionMap.get(userId);
        if (CollectionUtils.isNotEmpty(globalWebsocketList)) {
            for (GlobalWebsocket globalWebsocket : globalWebsocketList) {
                try {
                    globalWebsocket.session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    log.warn("websocket send message exception", e);
                }
            }
        }
    }

    /**
     * 发送新的消息通知
     *
     * @param userId      发送人id
     * @param name        发送人姓名
     * @param icon        发送人头像
     * @param detailsList 接收目标详情
     * @param content     发送消息内容
     */
    public static void sendNewMessage(Long userId, String name, String icon, List<UserMessageDetails> detailsList, String content) {
        for (UserMessageDetails details : detailsList) {
            if (isOnline(details.getUserId())) {
                NewSentMessage message = new NewSentMessage();
                message.setType(WebsocketMessageEnum.NEW_MESSAGE.getCode());
                message.setUserId(userId);
                message.setUsername(name);
                message.setUserPicture(icon);
                message.setId(details.getId());
                message.setContent(content);
                sendMessage(details.getUserId(), message);
            }
        }
    }

    /**
     * 删除消息通知
     *
     * @param userId      发送人id
     * @param name        发送人姓名
     * @param detailsList 接收目标详情
     */
    public static void deleteMessage(Long userId, String name, List<UserMessageDetails> detailsList) {
        for (UserMessageDetails details : detailsList) {
            if (isOnline(details.getUserId())) {
                DeletedMessage message = new DeletedMessage();
                message.setType(WebsocketMessageEnum.DELETE_MESSAGE.getCode());
                message.setUserId(userId);
                message.setUsername(name);
                message.setId(details.getId());
                sendMessage(details.getUserId(), message);
            }
        }
    }

    /**
     * 问题交流通知
     *
     * @param userId     发送人用户id
     * @param userName   发送人姓名
     * @param en         通知类型
     * @param studentIds 接收目标id
     */
    public static void problemCommunicationMessage(Long userId, String userName, WebsocketMessageEnum en, List<Long> studentIds) {
        for (Long studentId : studentIds) {
            if (isOnline(studentId)) {
                Message message = new ProblemCommunicationMessage();
                message.setType(en.getCode());
                message.setUserId(userId);
                message.setUsername(userName);
                sendMessage(studentId, message);
            }
        }
    }

    /**
     * 查询用户是否在线
     *
     * @param userId 用户Id
     */
    public static Boolean isOnline(Long userId) {
        return connectionMap.containsKey(userId);
    }
}
